﻿using HttpLib.Enum;
using HttpLib.Models;
using HttpLib.Util;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;

namespace HttpLib.Filters
{
    public class ApiSecurityFilter : ActionFilterAttribute, IActionFilter
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (context.Controller.GetType().Name.Equals("AccountController") ||
                context.Controller.GetType().Name.Equals("ConsentController") ||
                context.Controller.GetType().Name.Equals("HomeController")) 
            {
                base.OnActionExecuting(context);
                return;
            }
            try
            {
                var request = context.HttpContext.Request;
                string method = request.Method;
                string appKey = string.Empty,
                    timestamp = string.Empty,
                    nonce = string.Empty,
                    signature = string.Empty,
                    secret = string.Empty;
                var query = request.HttpContext.Request.Query;
                IDictionary<string, string> validateParameters = new Dictionary<string, string>();
                IDictionary<string, string> parameters = new Dictionary<string, string>();
                foreach (var item in query)
                {
                    if (item.Key.Equals("appkey"))
                    {
                        appKey = item.Value;
                        validateParameters.Add("appkey", appKey);
                    }
                    else if (item.Key.Equals("timestamp"))
                    {
                        timestamp = item.Value;
                        //时间戳必须在一分钟以内
                        //long currentTimeStamp = SignExtension.DateTimeToJsTimeStamp(DateTime.Now);
                        //if(currentTimeStamp - Convert.ToInt64(timestamp) > 60)
                        //{
                        //    context.Result = new ContentResult
                        //    {
                        //        StatusCode = (int)StatusCodeEnum.ParameterError,
                        //        Content = JsonConvert.SerializeObject(new ResultMsg { StatusCode = (int)StatusCodeEnum.HttpRequestError, Message = $"Api签名失败:{StatusCodeEnum.ParameterError.GetDescription()}" })
                        //    };
                        //    base.OnActionExecuting(context);
                        //    return;
                        //}
                        validateParameters.Add("timestamp", timestamp);
                    }
                    else if (item.Key.Equals("nonce"))
                    {
                        nonce = item.Value;
                        validateParameters.Add("nonce", nonce);
                    }
                    else if (item.Key.Equals("signature"))
                    {
                        signature = item.Value;
                    }
                    else
                    {
                        parameters.Add(item.Key, item.Value);
                    }
                }
                if (request.Headers.ContainsKey("secret"))
                {
                    secret = HttpUtility.UrlDecode(request.Headers["secret"].ToString());
                }
                #region token 不签名（取消）
                //Authentication方法不需要进行签名验证
                //if (((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor).ActionName == "Authentication")
                //{
                //    if (string.IsNullOrEmpty(appKey)  || string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(nonce))
                //    {
                //        context.Result = new ContentResult 
                //        {
                //            StatusCode = (int)StatusCodeEnum.ParameterError,
                //            Content = StatusCodeEnum.ParameterError.GetDescription(),
                //        };
                //        base.OnActionExecuting(context);
                //        return;
                //    }
                //    else
                //    {
                //        base.OnActionExecuting(context);
                //        return;
                //    }
                //}
                #endregion
                //判断请求头是否包含以下参数
                if (string.IsNullOrEmpty(appKey) || string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(nonce) || string.IsNullOrEmpty(signature))
                {
                    context.Result = new ContentResult
                    {
                        StatusCode = (int)StatusCodeEnum.ParameterError,
                        Content = JsonConvert.SerializeObject(new ResultMsg { StatusCode = (int)StatusCodeEnum.HttpRequestError, Message = $"Api签名失败:{StatusCodeEnum.ParameterError.GetDescription()}" })
                    };
                    base.OnActionExecuting(context);
                    return;
                }
                #region 传入参签名（已取消）
                //switch (method)
                //{
                //    case "POST":
                //    case "PUT":
                //        request.Body.Position = 0;
                //        var reader = new StreamReader(request.Body);
                //        string data = await reader.ReadToEndAsync();
                //        validateParameters.Add("data", data);
                //        break;
                //    case "GET":
                //        //把字典按Key的字母顺序排序
                //        IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
                //        IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
                //        //把所有参数名和参数值串在一起
                //        StringBuilder sb = new StringBuilder();
                //        while (dem.MoveNext())
                //        {
                //            string key = dem.Current.Key;
                //            string value = dem.Current.Value;
                //            if (!string.IsNullOrEmpty(key))
                //            {
                //                sb.Append(key).Append(value);
                //            }
                //        }
                //        data = query.ToString();
                //        validateParameters.Add("data", data);
                //        break;
                //    default:
                //        context.Result = new ContentResult
                //        {
                //            StatusCode = (int)StatusCodeEnum.ParameterError,
                //            Content = $"Api签名失败:{StatusCodeEnum.ParameterError.GetDescription()}",
                //        };
                //        base.OnActionExecuting(context);
                //        return;
                //}
                #endregion
                bool result = SignExtension.ValidateSign(validateParameters, signature, secret, false);
                if (!result)
                {
                    context.Result = new ContentResult
                    {
                        StatusCode = (int)StatusCodeEnum.HttpRequestError,
                        Content = JsonConvert.SerializeObject(new ResultMsg { StatusCode = (int)StatusCodeEnum.HttpRequestError, Message = $"Api签名失败:{StatusCodeEnum.ParameterError.GetDescription()}" })
                    };
                    base.OnActionExecuting(context);
                }
                else
                {
                    base.OnActionExecuting(context);
                }
            }
            catch(Exception ex)
            {
                context.Result = new ContentResult
                {
                    StatusCode = (int)StatusCodeEnum.HttpRequestError,
                    Content = JsonConvert.SerializeObject(new ResultMsg { StatusCode = (int)StatusCodeEnum.HttpRequestError, Message = $"Api签名失败:{ex.Message}" })
                };
                base.OnActionExecuting(context);
            }
           
        }

        public override void OnActionExecuted(ActionExecutedContext context)
        {
            base.OnActionExecuted(context);
        }
    }
}
